#include "kernel.h"
extern "C"{
void kerneltwo(
		IN_TYPE offset1[OFFSET_LEN],IN_TYPE adj1[ADJ_LEN],
		IN_TYPE offset2[OFFSET_LEN],IN_TYPE adj2[ADJ_LEN],
		IN_TYPE offset3[OFFSET_LEN],IN_TYPE adj3[ADJ_LEN],
		IN_TYPE offset4[OFFSET_LEN],IN_TYPE adj4[ADJ_LEN],
		IN_TYPE cand1[CAN_LEN],CAN_TYPE cand2[CAN2_LEN],CAN_TYPE findex[INDEX_LEN],CAN_TYPE cindex[INDEX_LEN],
		IN_TYPE size1,IN_TYPE size2,IN_TYPE index_size,IN_TYPE cindex_size,
		IN_TYPE pid1,IN_TYPE pid2,
		IN_TYPE out_buf[OUT_LEN]
		)
{
#pragma HLS INTERFACE m_axi port=cand1 offset=slave bundle=gmem0
#pragma HLS INTERFACE m_axi port=cand2 offset=slave bundle=gmem1
#pragma HLS INTERFACE m_axi port=out_buf offset=slave bundle=gmem2

#pragma HLS INTERFACE m_axi port=offset1 offset=slave bundle=gmem3
#pragma HLS INTERFACE m_axi port=adj1 offset=slave bundle=gmem4
#pragma HLS INTERFACE m_axi port=offset2 offset=slave bundle=gmem5
#pragma HLS INTERFACE m_axi port=adj2 offset=slave bundle=gmem6

#pragma HLS INTERFACE m_axi port=offset3 offset=slave bundle=gmem7
#pragma HLS INTERFACE m_axi port=adj3 offset=slave bundle=gmem8
#pragma HLS INTERFACE m_axi port=offset4 offset=slave bundle=gmem9
#pragma HLS INTERFACE m_axi port=adj4 offset=slave bundle=gmem10
#pragma HLS INTERFACE m_axi port=findex offset=slave bundle=gmem11
#pragma HLS INTERFACE m_axi port=cindex offset=slave bundle=gmem12

#pragma HLS INTERFACE s_axilite port=offset1 bundle=control
#pragma HLS INTERFACE s_axilite port=adj1 bundle=control
#pragma HLS INTERFACE s_axilite port=offset2 bundle=control
#pragma HLS INTERFACE s_axilite port=adj2 bundle=control
#pragma HLS INTERFACE s_axilite port=offset3 bundle=control
#pragma HLS INTERFACE s_axilite port=adj3 bundle=control
#pragma HLS INTERFACE s_axilite port=offset4 bundle=control
#pragma HLS INTERFACE s_axilite port=adj4 bundle=control

#pragma HLS INTERFACE s_axilite port=cand1 bundle=control
#pragma HLS INTERFACE s_axilite port=cand2 bundle=control
#pragma HLS INTERFACE s_axilite port=out_buf bundle=control
#pragma HLS INTERFACE s_axilite port=findex bundle=control
#pragma HLS INTERFACE s_axilite port=cindex bundle=control
#pragma HLS INTERFACE s_axilite port=size1 bundle=control
#pragma HLS INTERFACE s_axilite port=size2 bundle=control
#pragma HLS INTERFACE s_axilite port=index_size bundle=control
#pragma HLS INTERFACE s_axilite port=cindex_size bundle=control
#pragma HLS INTERFACE s_axilite port=pid1 bundle=control
#pragma HLS INTERFACE s_axilite port=pid2 bundle=control
#pragma HLS INTERFACE s_axilite port=return bundle=control
	IN_TYPE size_c1 = 0;
	IN_TYPE size_c2 = 0;
	IN_TYPE size_i = 0;

	IN_TYPE pre_adj_count = 0;
	IN_TYPE pre_head = END_FLAG,pre_value = END_FLAG;
	IN_TYPE pre_end = 0,pre_begin = 0,pre_i=0,pre_size=0;

	IN_TYPE pre_adj_count2 = 0;
	IN_TYPE pre_head2 = END_FLAG,pre_value2 = END_FLAG;
	IN_TYPE pre_end2 = 0,pre_begin2 = 0,pre_i2=0,pre_size2=0;

	static IN_TYPE pre_off_buffer[32];
	static IN_TYPE pre_adj_buffer[40960];

	static IN_TYPE pre_off_buffer2[32];
	static IN_TYPE pre_adj_buffer2[81920];

	//static CAN_TYPE block_buffer[512];

	static IN_TYPE preid1;
	static IN_TYPE preid2;
	static IN_TYPE cand1_buffer[1024][16];
	static IN_TYPE cand1_count = 0;
	static IN_TYPE cand1_bf_count[1024];
#pragma HLS BIND_STORAGE variable=cand1_bf_count type=ram_2p
	static IN_TYPE a1_count=0;
	static IN_TYPE a2_count=0;
	static IN_TYPE a1_cache[4096];
	static IN_TYPE a2_cache[4096];
	static CAN_TYPE index_buffer[212256];
#pragma HLS BIND_STORAGE variable=index_buffer type=ram_2p impl=uram
	static CAN_TYPE cindex_buffer[848672];
	static IN_TYPE cand2_bf_count = 0;
	static IN_TYPE out_count=0;
	static IN_TYPE cand2_count = 0;
	static IN_TYPE out_iter = 0;
	IN_TYPE i,j,tmp,tmp2,begin,end,begin2,end2,adj_size,adj_size2,iter,jj,kk,index,a1c,a2c,former1,former2,efcount,efoff,bi,blc_begin,ci,csize;
	int bid,off,bbid,boff,pre_bbid,cbid,coff;
	CAN_TYPE tmpblock,tmpblock2,tmpblock3,tmptype,tmpblock4,tmpblock5,tmpblock6,tmpblock7,tmpblock8,tmpblock9;
	size_c1=0;
	size_c2=0;
	pre_bbid = 0;
	preid1=13;
	preid2=5;
	a1_count=0;
	a2_count=0;
	a1c=0;
	a2c=0;
	out_count=0;
	cand1_count=0;
	cand2_bf_count=0;
	out_iter=0;
	i=0;
	j=0;
	begin=0;
	end=0;
	adj_size=0;
	iter=0;
	jj=0;
	kk=0;
	index=0;
	former1=END_FLAG;
	former2=END_FLAG;
	size_c1 = size1;
	size_c2 = size2;
	size_i = index_size;
	csize = cindex_size;
	preid1 = pid1;
	preid2 = pid2;
	blc_begin = 0;

	INDEX_LOAD:for(i=0;i<size_i;i++){
		index_buffer[i] = findex[i];
	}
	CINDEX_LOAD:for(ci=0;ci<csize;ci++){
		cindex_buffer[ci] = cindex[ci];
	}

	for(;cand1_count<size1;){
		//cout<<"a new iteration"<<endl;
		INITIAL2:for(i=0;i<1024;i++){
			cand1_bf_count[i]=0;
			cand1_bf_count[i+1]=0;
		}

		CAND1_LOAD_OUTTER:for(i=0;i<1024 && cand1_count<size1;i++){
			tmp = cand1[cand1_count];
			cand1_count++;
			tmp2 = cand1[cand1_count];
			cand1_count++;
			cand1_buffer[i][0]=tmp;
			cand1_bf_count[i]++;
			cand1_buffer[i][1]=tmp2;
			cand1_bf_count[i]++;
			if(preid1==13){
				if(pre_head==END_FLAG || tmp - pre_head > 30){
					pre_head = tmp;
					for(pre_i=0;pre_i<32;pre_i++){
						pre_off_buffer[pre_i] = offset2[tmp+pre_i];
					}
					pre_begin = pre_off_buffer[0];
					pre_end = pre_off_buffer[31];
					pre_size = pre_end - pre_begin;
					for(pre_i=0;pre_i<pre_size;pre_i++){
						pre_adj_buffer[pre_i] = adj2[pre_begin+pre_i];
					}
				}
				a1_count=0;
				begin = pre_off_buffer[tmp - pre_head] - pre_begin;
				end = pre_off_buffer[tmp - pre_head + 1] - pre_begin;
				adj_size = end - begin;
				READ_ADJ1:for(iter=0;iter<adj_size;iter++){
					a1_cache[a1_count++] = pre_adj_buffer[iter+begin];
				}

				if(pre_head2 == END_FLAG || tmp2 - pre_head2 > 0){
					pre_head2 = tmp2;
					for(pre_i2=0;pre_i2<2;pre_i2++){
						pre_off_buffer2[pre_i2] = offset1[tmp2+pre_i2];
					}
					pre_begin2 = pre_off_buffer2[0];
					pre_end2 = pre_off_buffer2[1];
					pre_size2 = pre_end2 - pre_begin2;
					for(pre_i2=0;pre_i2<pre_size2;pre_i2++){
						pre_adj_buffer2[pre_i2] = adj1[pre_begin2+pre_i2];
					}
				}
				a2_count=0;
				begin2 = pre_off_buffer2[tmp2 - pre_head2] - pre_begin2;
				end2 = pre_off_buffer2[tmp2 - pre_head2 + 1] - pre_begin2;
				adj_size2 = end2 - begin2;
				READ_ADJ2:for(iter=0;iter<adj_size2;iter++){
					a2_cache[a2_count++] = pre_adj_buffer2[iter+begin2];
				}
			}else{
				if(pre_head==END_FLAG || tmp - pre_head > 10){
					pre_head = tmp;
					for(pre_i=0;pre_i<12;pre_i++){
						pre_off_buffer[pre_i] = offset4[tmp+pre_i];
					}
					pre_begin = pre_off_buffer[0];
					pre_end = pre_off_buffer[11];
					pre_size = pre_end - pre_begin;
					for(pre_i=0;pre_i<pre_size;pre_i++){
						pre_adj_buffer[pre_i] = adj4[pre_begin+pre_i];
					}
				}
				a1_count=0;
				begin = pre_off_buffer[tmp - pre_head] - pre_begin;
				end = pre_off_buffer[tmp - pre_head + 1] - pre_begin;
				adj_size = end - begin;
				READ_ADJ3:for(iter=0;iter<adj_size;iter++){
					a1_cache[a1_count++] = pre_adj_buffer[iter+begin];
				}

				if(pre_head2 == END_FLAG || tmp2 - pre_head2 > 30){
					pre_head2 = tmp2;
					for(pre_i2=0;pre_i2<32;pre_i2++){
						pre_off_buffer2[pre_i2] = offset3[tmp2+pre_i2];
					}
					pre_begin2 = pre_off_buffer2[0];
					pre_end2 = pre_off_buffer2[31];
					pre_size2 = pre_end2 - pre_begin2;
					for(pre_i2=0;pre_i2<pre_size2;pre_i2++){
						pre_adj_buffer2[pre_i2] = adj3[pre_begin2+pre_i2];
					}
				}
				a2_count=0;
				begin2 = pre_off_buffer2[tmp2 - pre_head2] - pre_begin2;
				end2 = pre_off_buffer2[tmp2 - pre_head2 + 1] - pre_begin2;
				adj_size2 = end2 - begin2;
				READ_ADJ4:for(iter=0;iter<adj_size2;iter++){
					a2_cache[a2_count++] = pre_adj_buffer2[iter+begin2];
				}
			}

			for(a1c = 0, a2c = 0; a1c < a1_count && a2c < a2_count;){
				if(a1_cache[a1c]>a2_cache[a2c]){
					a2c++;
				}else if(a1_cache[a1c]<a2_cache[a2c]){
					a1c++;
				}else{
					cand1_buffer[i][cand1_bf_count[i]] = a1_cache[a1c];
					//cout<<"finding commen element: "<<a1_cache[a1c]<<endl;
					a1c++;
					a2c++;
					cand1_bf_count[i]++;
				}
			}
		}


		for(i=0;i<1024;i++){
			for(jj=2;jj<cand1_bf_count[i];jj++){

				bbid = cand1_buffer[i][jj] / 4096;
				cbid = cand1_buffer[i][jj] / 1024;
				boff = (cand1_buffer[i][jj] / 512) % 8;
				coff = cand1_buffer[i][jj] % 8;
				tmpblock4 = index_buffer[bbid];
				tmpblock7 = cindex_buffer[cbid];
				tmpblock5 = 1<<(7-boff);
				tmpblock8 = 1<<(7-coff);
				tmpblock6 = tmpblock4&tmpblock5;
				tmpblock9 = tmpblock7&tmpblock8;
				if(tmpblock5==tmpblock6&&tmpblock9==tmpblock8){
					/*
					if(bbid != pre_bbid){
						blc_begin = bbid * 512;
						for(bi=0;bi<512;bi++){
							block_buffer[bi] = cand2[blc_begin+bi];
						}
					}
					*/
					//pre_bbid = bbid;
					//bid = (cand1_buffer[i][jj] % 4096) / 8;
					bid = cand1_buffer[i][jj] / 8;
					off = cand1_buffer[i][jj] % 8;
					tmpblock = cand2[bid];
					tmpblock2 = 1<<(7-off);
					tmpblock3 = tmpblock&tmpblock2;
					if(tmpblock3 == tmpblock2){
						out_buf[out_count++] = cand1_buffer[i][0];
						out_buf[out_count++] = cand1_buffer[i][1];
						out_buf[out_count++] = cand1_buffer[i][jj];
					}
				}

			}
		}
	}
	efcount = out_count % 64;
	efoff = 64 - efcount + 1;
	for(i=0;i<efoff;i++){
		out_buf[out_count] = END_FLAG;
		out_count++;
	}
}
}
